Skip to content

feat: multi-battle for stations#1205

Open
Mygod wants to merge 45 commits intoWatWowMap:developfrom
Mygod:multibattle
Open

feat: multi-battle for stations#1205
Mygod wants to merge 45 commits intoWatWowMap:developfrom
Mygod:multibattle

Conversation

@Mygod
Copy link
Copy Markdown
Collaborator

@Mygod Mygod commented Apr 6, 2026

Mygod added 30 commits April 4, 2026 20:11
@Mygod Mygod added the Enhancement New feature or request label Apr 6, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbe7b45c02

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds multi-battle support for Stations end-to-end (DB context detection → API/model aggregation → GraphQL schema/queries → UI rendering), with an additional client filter to optionally include upcoming battles.

Changes:

  • Extend the Station GraphQL/API shape to include a battles array (StationBattle) and plumb it through client queries/types.
  • Update Station map marker, tile memoization, and popup UI to handle multiple battles and a “Include Upcoming” filter.
  • Update station search results timing to account for battle_start (pre-start vs active).

Reviewed changes

Copilot reviewed 17 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/services/queries/station.js Fetches battles { ... } for station details.
src/services/queries/search.js Adds battle_start to search results query.
src/features/station/useStationMarker.js Marker icon logic updated to accept a selected battle.
src/features/station/StationTile.jsx Computes battle-derived timers/state and memoizes based on battles.
src/features/station/StationPopup.jsx Renders multiple battles in the popup; integrates filtering/visibility.
src/features/station/battleState.js New shared client helper for selecting/ordering battles + refresh timestamps.
src/features/search/renderOption.jsx Search option timer updated to consider battle_start.
src/features/search/OptionImage.jsx Simplifies memoization for option images.
src/features/drawer/Stations.jsx Adds “Include Upcoming” toggle to station filters UI.
server/src/services/DbManager.js Detects station_battle table support via schema check (hasMultiBattles).
server/src/models/Station.js Implements multi-battle joins/aggregation, filtering, and search support.
server/src/graphql/typeDefs/scanner.graphql Adds battles: [StationBattle] and defines StationBattle.
server/src/graphql/typeDefs/map.graphql Adds battle_start to Search type.
server/src/filters/builder/base.js Adds default filter field includeUpcoming when permitted.
packages/types/lib/server.d.ts Adds hasMultiBattles to DB context type.
packages/types/lib/scanner.d.ts Adds StationBattle + Station.battles typings.
packages/locales/lib/human/en.json Adds include_upcoming label.
config/default.json Adds default stations.includeUpcoming: true.
config/custom-environment-variables.json Adds env override mapping for default includeUpcoming.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +96 to +103
const [now, setNow] = React.useState(() => Math.floor(Date.now() / 1000))
React.useEffect(() => {
const interval = setInterval(() => {
setNow(Math.floor(Date.now() / 1000))
}, 1000)
return () => clearInterval(interval)
}, [])
const target = startTime > now ? startTime : expireTime
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timer sets up its own 1s setInterval to update now, but it also calls useRelativeTimer, which already creates its own 1s interval. In the search dropdown this can create 2 intervals per rendered option row, which is a measurable performance/CPU hit.

Consider avoiding the extra interval by scheduling a single setTimeout for the start->end transition (only when startTime is in the future), or by enhancing useRelativeTimer/a shared hook to handle { startTime, expireTime } switching internally with one ticker.

Suggested change
const [now, setNow] = React.useState(() => Math.floor(Date.now() / 1000))
React.useEffect(() => {
const interval = setInterval(() => {
setNow(Math.floor(Date.now() / 1000))
}, 1000)
return () => clearInterval(interval)
}, [])
const target = startTime > now ? startTime : expireTime
const [target, setTarget] = React.useState(() =>
startTime > Math.floor(Date.now() / 1000) ? startTime : expireTime,
)
React.useEffect(() => {
const now = Math.floor(Date.now() / 1000)
if (startTime > now) {
setTarget(startTime)
const timeout = setTimeout(() => {
setTarget(expireTime)
}, Math.max(startTime * 1000 - Date.now(), 0))
return () => clearTimeout(timeout)
}
setTarget(expireTime)
}, [expireTime, startTime])

Copilot uses AI. Check for mistakes.
Comment on lines +481 to +485
<StationBattleTimer
epoch={battleEndEpoch}
updated={updated}
countdown={showLiveCountdown}
hidden={hidden}
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upcoming battles (where battle_start is in the future) currently won’t show a start-time countdown: countdown is only enabled for isBattleActive, and the timer is always driven by battleEndEpoch. This means upcoming battles render an ends time with no countdown.

Consider driving the timer with battleStartEpoch (label starts) while battleStartEpoch > nowSeconds, then switch to battleEndEpoch once active.

Copilot uses AI. Check for mistakes.
Comment on lines +809 to +815
<Typography variant="subtitle1" align="center" color={textColor}>
{t('ends')}: {timeFormatter.format(new Date(target))}
</Typography>
{countdown ? (
<Typography variant="h6" align="center" color={textColor}>
{relativeTime}
</Typography>
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StationBattleTimer always labels the timestamp as ends, even when it’s being used for non-active/hidden battles. If you implement upcoming-battle countdowns (to battle_start), this component will also need a way to render starts vs ends (e.g., a label/start prop).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants